package com.mianyang.zhangsan.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.mianyang.zhangsan.common.constant.SecConstant;
import com.mianyang.zhangsan.common.util.CacheHelper;
import com.mianyang.zhangsan.common.util.CommonUtils;
import com.mianyang.zhangsan.common.util.FileUtils;
import com.mianyang.zhangsan.common.util.NameGenerator;
import com.mianyang.zhangsan.common.util.StringUtils;
import com.mianyang.zhangsan.exception.SecServiceException;
import com.mianyang.zhangsan.model.dto.SecPaperDto;
import com.mianyang.zhangsan.model.dto.SecProblemDto;
import com.mianyang.zhangsan.model.entity.SecAnswer;
import com.mianyang.zhangsan.model.entity.SecPaper;
import com.mianyang.zhangsan.model.entity.SecPaperInst;
import com.mianyang.zhangsan.model.entity.SecProblemInst;
import com.mianyang.zhangsan.model.entity.SecStaticData;
import com.mianyang.zhangsan.plugin.export.AbstractTemplate;
import com.mianyang.zhangsan.plugin.export.WordTemplate;
import com.mianyang.zhangsan.plugin.oss.MinioService;
import com.mianyang.zhangsan.service.ISecPaperExportService;
import com.mianyang.zhangsan.service.SecPaperInstService;
import com.mianyang.zhangsan.service.SecStaticDataService;
import com.mianyang.zhangsan.service.SecTemplateService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * @author jiangjr
 * @date 2022-12-02
 */
@Slf4j
@Service
public class SecPaperExportServiceImpl implements ISecPaperExportService {
    @Autowired
    private SecPaperInstService paperInstService;
    @Autowired
    private SecTemplateService templateService;
    @Autowired
    private MinioService minioService;
    @Autowired
    private SecStaticDataService staticDataService;


    @Override
    public String generateAndUpload(Long paperInstId) {
        // 查询试卷信息，封装数据
        SecPaperDto paper = paperInstService.selectPracticeInfo(paperInstId);
        Map<String, Object> variables = parserPaper(paper);
        // 获取模板编号,查询模板路径
        Long templateId = paper.getPaper().getTemplateId();
        String templatePath = templateService.selectTemplatePath(templateId);
        if (StringUtils.isEmpty(templatePath)) {
            templatePath = SecConstant.DEFAULT_PAPER_TEMPLATE;
        }
        String paperPath = null;
        InputStream in = null;
        OutputStream out = null;
        try {
            // 下载模板
            in = FileUtils.readWebFile(templatePath);
            AbstractTemplate templateGenerator = new WordTemplate(in);
            // 调用填充模板方法，生成试卷
            out = templateGenerator.build(variables);
            // 上传试卷至文件服务器
            // 生成文件名
            String fileName = NameGenerator.currentDateAsName(paper.getPaper().getPaperName());
            fileName = fileName + ".docx";
            MultipartFile multipartFile = FileUtils.readMultipartFile(out, fileName);
            paperPath = minioService.uploadFile(multipartFile, null);
        } catch (Exception e) {
            log.error("生成试卷文档失败-{}", e.getMessage());
            throw new SecServiceException("生成试卷文档失败");
        }finally {
            try {
                if (in != null) {
                    in.close();
                }
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                // do nothing
            }
        }
        // 返回文件上传地址，写回试卷实例中
        SecPaperInst paperInst = SecPaperInst.builder()
                .paperInstId(paperInstId)
                .paperPath(paperPath).build();
        paperInstService.updateById(paperInst);
        return paperPath;
    }

    @Override
    public String download(Long paperInstId) {
        // 查询试卷是否已经上传
        SecPaperInst paperInst = paperInstService.getById(paperInstId);
        if (StringUtils.isNotEmpty(paperInst.getPaperPath())) {
            return paperInst.getPaperPath();
        }
        // 没有上传-生成试卷
        return generateAndUpload(paperInstId);
    }

    private Map<String, Object> parserPaper(SecPaperDto paper) {
        Map<String, Object> map = new HashMap<>();
        SecPaper secPaper = paper.getPaper();
        // 设置试卷名称
        map.put("paperName", secPaper.getPaperName());
        // 设置公司名称
        map.put("companyName", SecConstant.SEC_COMPANY_NAME);
        map.put("score", secPaper.getPaperScore());
        map.put("formatTime", parserTime(secPaper.getLimitTime()));
        String paperType = "";
        List<SecStaticData> paperTypeDataList = staticDataService.getCache("PAPER_TYPE", "");
        if (CommonUtils.isNotEmpty(paperTypeDataList)) {
            Optional<SecStaticData> paperTypeData = paperTypeDataList.stream().filter(data -> data.getCodeValue().equals(String.valueOf(secPaper.getPaperType())))
                    .findFirst();
            if (paperTypeData.isPresent()) {
                paperType = paperTypeData.get().getCodeName();
            }
        }
        map.put("paperType", paperType);
        JSONArray problemArray = new JSONArray();
        // 设置题目和答案
        List<SecProblemDto> problems = paper.getProblems();
        for (int i = 0; i < problems.size(); i++) {
            JSONObject problemInfo = new JSONObject();
            SecProblemInst currentProblem = problems.get(i).getProblem();
            List<SecAnswer> answers = problems.get(i).getAnswers();
            String problemDesc = (i + 1) + "、" + currentProblem.getProblemDesc();
            JSONArray answerArray = new JSONArray();
            for (int j = 0; j < answers.size(); j++) {
                JSONObject answerInfo = new JSONObject();
                String answerDesc = SecConstant.CHOOSE_OF_CHAR[j] + "、" + answers.get(j).getAnswer();
                answerInfo.put("answer", answerDesc);
                answerArray.add(answerInfo);
            }
            problemInfo.put("problemDesc", problemDesc);
            problemInfo.put("answers", answerArray);
            problemArray.add(problemInfo);
        }
        map.put("problems", problemArray);
        return map;
    }

    private String parserTime(long limitTime) {
        long min = limitTime / 1000 / 60;
        return min + "分钟";
    }
}
